package tools

import (
	"bytes"
	"encoding/json"
	"fmt"
	"mcp-clarification-service/internal/protocol"
	"strings"

	"github.com/google/uuid"
)

// Adapter 工具适配器
//
// defaultTimeout <= 0 表示无限等待
type Adapter struct {
	defaultTimeout int
}

// NewAdapter 创建新的适配器
func NewAdapter(defaultTimeout int) *Adapter {
	return &Adapter{defaultTimeout: defaultTimeout}
}

func (a *Adapter) resolveTimeout(value int) int {
	if value > 0 {
		return value
	}
	if a.defaultTimeout > 0 {
		return a.defaultTimeout
	}
	return 0
}

// ToAskQuestionsRequest 将单题工具转换为批量请求
func (a *Adapter) ToAskQuestionsRequest(toolName string, params json.RawMessage) ([]Question, int, error) {
	switch toolName {
	case "ask_single_choice":
		var input SingleChoiceInput
		if err := json.Unmarshal(params, &input); err != nil {
			return nil, 0, fmt.Errorf("invalid parameters: %w", err)
		}
		timeout := a.resolveTimeout(input.Timeout)
		cleaned := make([]string, 0, len(input.Options))
		for _, opt := range input.Options {
			if trimmed := strings.TrimSpace(opt); trimmed != "" {
				cleaned = append(cleaned, trimmed)
			}
		}
		if len(cleaned) < 2 {
			return nil, 0, fmt.Errorf("single choice requires at least 2 non-empty options")
		}
		return []Question{{
			ID:       uuid.New().String(),
			Type:     "single",
			Question: input.Question,
			Options:  cleaned,
		}}, timeout, nil

	case "ask_multiple_choice":
		var input MultipleChoiceInput
		if err := json.Unmarshal(params, &input); err != nil {
			return nil, 0, fmt.Errorf("invalid parameters: %w", err)
		}
		timeout := a.resolveTimeout(input.Timeout)
		cleaned := make([]string, 0, len(input.Options))
		for _, opt := range input.Options {
			if trimmed := strings.TrimSpace(opt); trimmed != "" {
				cleaned = append(cleaned, trimmed)
			}
		}
		if len(cleaned) < 2 {
			return nil, 0, fmt.Errorf("multiple choice requires at least 2 non-empty options")
		}
		return []Question{{
			ID:       uuid.New().String(),
			Type:     "multiple",
			Question: input.Question,
			Options:  cleaned,
		}}, timeout, nil

	case "ask_free_text":
		var input FreeTextInput
		if err := json.Unmarshal(params, &input); err != nil {
			return nil, 0, fmt.Errorf("invalid parameters: %w", err)
		}
		timeout := a.resolveTimeout(input.Timeout)
		return []Question{{
			ID:          uuid.New().String(),
			Type:        "free_text",
			Question:    input.Question,
			Placeholder: input.Placeholder,
		}}, timeout, nil

	case "ask_questions":
		var input AskQuestionsInput
		if err := json.Unmarshal(params, &input); err != nil {
			return nil, 0, fmt.Errorf("invalid parameters: %w", err)
		}
		timeout := a.resolveTimeout(input.Timeout)
		normalized := make([]Question, len(input.Questions))
		for i, q := range input.Questions {
			if strings.TrimSpace(q.ID) == "" {
				q.ID = uuid.New().String()
			}

			switch q.Type {
			case "single", "multiple":
				cleaned := make([]string, 0, len(q.Options))
				for _, opt := range q.Options {
					if trimmed := strings.TrimSpace(opt); trimmed != "" {
						cleaned = append(cleaned, trimmed)
					}
				}
				if len(cleaned) < 2 {
					return nil, 0, fmt.Errorf("question %d ('%s') of type '%s' requires at least 2 options", i+1, q.Question, q.Type)
				}
				q.Options = cleaned
			case "free_text":
			default:
				return nil, 0, fmt.Errorf("invalid question type '%s' at index %d", q.Type, i)
			}

			normalized[i] = q
		}
		return normalized, timeout, nil

	default:
		return nil, 0, fmt.Errorf("unknown tool: %s", toolName)
	}
}

// FromAskQuestionsResponse 将批量响应转换为工具输出
func (a *Adapter) FromAskQuestionsResponse(toolName string, answers []Answer, cancelled bool) (*protocol.ToolResult, error) {
	if cancelled {
		return &protocol.ToolResult{
			Content: []protocol.ContentItem{
				protocol.NewTextContent(fmt.Sprintf(`{"cancelled": true}`)),
			},
		}, nil
	}

	if len(answers) == 0 {
		return nil, fmt.Errorf("no answers received")
	}

	answer := answers[0]

	switch toolName {
	case "ask_single_choice":
		selectedIndex := -1
		if answer.SelectedIndex != nil {
			selectedIndex = *answer.SelectedIndex
		} else if answer.AdditionalInput == "" {
			return nil, fmt.Errorf("no option selected")
		}
		output := SingleChoiceOutput{
			SelectedIndex:   selectedIndex,
			SelectedOption:  "",
			AdditionalInput: answer.AdditionalInput,
			Cancelled:       false,
		}
		buffer := &bytes.Buffer{}
		encoder := json.NewEncoder(buffer)
		encoder.SetEscapeHTML(false)
		if err := encoder.Encode(output); err != nil {
			return nil, fmt.Errorf("failed to encode output: %w", err)
		}
		data := bytes.TrimRight(buffer.Bytes(), "\n")
		return &protocol.ToolResult{
			Content: []protocol.ContentItem{
				protocol.NewTextContent(string(data)),
			},
		}, nil

	case "ask_multiple_choice":
		output := MultipleChoiceOutput{
			SelectedIndices: answer.SelectedIndices,
			SelectedOptions: []string{},
			AdditionalInput: answer.AdditionalInput,
			Cancelled:       false,
		}
		buffer := &bytes.Buffer{}
		encoder := json.NewEncoder(buffer)
		encoder.SetEscapeHTML(false)
		if err := encoder.Encode(output); err != nil {
			return nil, fmt.Errorf("failed to encode output: %w", err)
		}
		data := bytes.TrimRight(buffer.Bytes(), "\n")
		return &protocol.ToolResult{
			Content: []protocol.ContentItem{
				protocol.NewTextContent(string(data)),
			},
		}, nil

	case "ask_free_text":
		output := FreeTextOutput{
			Answer:    answer.Text,
			Cancelled: false,
		}
		buffer := &bytes.Buffer{}
		encoder := json.NewEncoder(buffer)
		encoder.SetEscapeHTML(false)
		if err := encoder.Encode(output); err != nil {
			return nil, fmt.Errorf("failed to encode output: %w", err)
		}
		data := bytes.TrimRight(buffer.Bytes(), "\n")
		return &protocol.ToolResult{
			Content: []protocol.ContentItem{
				protocol.NewTextContent(string(data)),
			},
		}, nil

	case "ask_questions":
		output := AskQuestionsOutput{
			Answers:   answers,
			Cancelled: false,
		}
		buffer := &bytes.Buffer{}
		encoder := json.NewEncoder(buffer)
		encoder.SetEscapeHTML(false)
		if err := encoder.Encode(output); err != nil {
			return nil, fmt.Errorf("failed to encode output: %w", err)
		}
		data := bytes.TrimRight(buffer.Bytes(), "\n")
		return &protocol.ToolResult{
			Content: []protocol.ContentItem{
				protocol.NewTextContent(string(data)),
			},
		}, nil

	default:
		return nil, fmt.Errorf("unknown tool: %s", toolName)
	}
}
